package com.yunji.generate.fxml;

import com.yunji.generate.bean.TableInfo;
import com.yunji.generate.common.BeanConfig;
import com.yunji.generate.common.DatabaseConfig;
import com.yunji.generate.service.BeanGenerator;
import com.yunji.generate.service.DatabaseHelper;
import com.yunji.generate.service.IProcessCallback;
import com.yunji.generate.util.ResourceUtil;
import com.yunji.generate.util.StringUtil;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.stage.Window;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * 主窗体
 *
 * @author hushuang
 * @since 2019/9/22
 */
public class MainFrameController extends BaseController {

    @FXML
    private Label progressLabel;

    @FXML
    private ProgressBar progressBar;

    @FXML
    private TextField packageNameText;

    @FXML
    private TextField authorText;

    @FXML
    private TextField tablePrefixText;

    @FXML
    private TextField usernameText;

    @FXML
    private TextField passwordText;

    @FXML
    private TextField urlText;

    @FXML
    private CheckBox swaggerCheckBox;

    @FXML
    private CheckBox excelCheckBox;

    @FXML
    private CheckBox lombokCheckBox;

    @FXML
    private Button generateButton;

    @FXML
    private Button openCodePathButton;

    @FXML
    private TableView<TableInfo> table;
    @FXML
    private TableColumn<TableInfo, String> tableColumn1;
    @FXML
    private TableColumn<TableInfo, Boolean> tableColumn2;
    @FXML
    private TableColumn<TableInfo, Boolean> tableColumn3;

    private ObservableList<TableInfo> tableData = FXCollections.observableArrayList();

    private String fullSavePath;

    @FXML
    private void initialize() {
        tableColumn1.setCellValueFactory(new PropertyValueFactory<>("name"));

        tableColumn2.setCellValueFactory(new PropertyValueFactory<>("swaggerSupported"));
        tableColumn2.setCellFactory(p -> new BooleanCell<>(!swaggerCheckBox.isDisable()));

        tableColumn3.setCellValueFactory(new PropertyValueFactory<>("excelSupported"));
        tableColumn3.setCellFactory(p -> new BooleanCell<>(!excelCheckBox.isDisable()));

        table.setItems(tableData);

        // 测试数据 refreshTable(Collections.singletonList(new TableInfo("t_cloud_warehouse_out", "应收表")));
    }

    @FXML
    public void onGenerateButtonClick(ActionEvent event) {
        String path = chooseSavePath(stage(event));
        if (path == null) {
            return;
        }
        // 测试数据       String path = "C:\\Users\\LENOVO\\Desktop\\generate";

        // 获取数据表详细数据
        List<TableInfo> sourceData = getTableData();
        DatabaseHelper.asyncTables(getDatabaseConfig(), sourceData, new IProcessCallback<TableInfo>() {

            @Override
            public boolean onProcessing(Parameter<TableInfo> p) {
                refreshProgress(p.sequence, sourceData.size());
                return false;
            }

            @Override
            public void onProcessEnd(ListParameter<TableInfo> p) {
                progressBar.setProgress(1);
                doGenerate(p.source, path);
            }
        });
    }

    private void doGenerate(List<TableInfo> data, String path) {
        // 生成代码
        BeanConfig beanConfig = new BeanConfig();
        beanConfig.setPackageName(packageNameText.getText().trim());
        beanConfig.setAuthor(authorText.getText().trim());
        beanConfig.setLombokSupported(lombokCheckBox.isSelected());
        beanConfig.setTables(data);
        beanConfig.setSavePath(path);

        beanConfig.setTablePrefixes(
                Stream.of(tablePrefixText.getText().split(",")).map(String::trim).collect(Collectors.toList()));

        try {
            openCodePathButton.setDisable(true);
            openCodePathButton.setTooltip(null);
            fullSavePath = BeanGenerator.generate(beanConfig);
            openCodePathButton.setTooltip(new Tooltip(path));
            openCodePathButton.setDisable(false);

            onOpenCodePathButtonClick();
        } catch (Exception e) {
            e.printStackTrace();
            showMessage(e.getMessage());
        }
    }

    private void refreshProgress(int current, int max) {
        progressBar.setProgress(current / (double) max);
        Platform.runLater(() -> progressLabel.setText(String.format("%d/%d", current, max)));
    }

    private String chooseSavePath(Window window) {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择存放目录");
        directoryChooser.initialDirectoryProperty();
        File path = directoryChooser.showDialog(window);
        return path == null ? null : path.getAbsolutePath();
    }

    private List<TableInfo> getTableData() {
        return new ArrayList<>(tableData);
    }

    private DatabaseConfig getDatabaseConfig() {
        String url = urlText.getText().trim();
        String username = usernameText.getText().trim();
        String password = passwordText.getText().trim();
        return new DatabaseConfig(url, username, password);
    }

    @FXML
    public void onOpenCodePathButtonClick() {
        if (StringUtil.isEmpty(fullSavePath)) {
            showMessage("不能打开目录，因为路径为空");
            return;
        }
        try {
            Desktop.getDesktop().open(new File(fullSavePath));
        } catch (IOException e) {
            e.printStackTrace();
            showMessage(e.getMessage());
        }
    }

    @SuppressWarnings("unchecked")
    @FXML
    public void onChooseTableButtonClick(ActionEvent event) throws IOException {
        List<TableInfo> source = DatabaseHelper.getTableSimpleInfo(getDatabaseConfig());
        hide(event);

        FXMLLoader fxmlLoader = new FXMLLoader(MainFrameController.class.getResource("/fxml/ChooseFrame.fxml"));
        Parent root = fxmlLoader.load();
        ChooseFrameController controller = fxmlLoader.getController();
        controller.initTableData(source);

        Stage newStage = new Stage();
        newStage.setTitle("选择数据表");
        newStage.getIcons().add(ResourceUtil.LOGO_JAVAFX);
        newStage.setScene(new Scene(root, 700, 600));
        newStage.setOnHidden(e -> {
            // 关闭选择窗体后，更新表格数据
            List<TableInfo> data = (List<TableInfo>) newStage.getUserData();
            if (data != null) {
                // 不清空，只做追加
                refreshTable(data);
                generateButton.setDisable(false);
            }
            stage(event).show();
        });
        newStage.show();
    }

    @FXML
    public void onSwaggerCheckBoxClicked() {
        refreshTable();
    }

    @FXML
    public void onExcelCheckBoxClicked() {
        refreshTable();
    }

    @FXML
    public void onClearTableButtonClicked() {
        generateButton.setDisable(true);
        tableData.clear();
        table.refresh();
        refreshProgress(0, 0);
    }

    private void refreshTable(List<TableInfo> data) {
        List<String> tableNames = tableData.stream().map(TableInfo::getName).collect(Collectors.toList());
        tableData.addAll(data.stream().filter(e -> !tableNames.contains(e.getName())).collect(Collectors.toList()));
        refreshProgress(0, tableData.size());
        refreshTable();
    }

    private void refreshTable() {
        boolean isSwaggerSelected = swaggerCheckBox.isSelected();
        boolean isExcelSelected = excelCheckBox.isSelected();
        tableData.forEach(e -> {
            e.setSwaggerSupported(isSwaggerSelected);
            e.setExcelSupported(isExcelSelected);
        });
        table.refresh();
    }

    private void showMessage(String message) {
        Alert alert = new Alert(Alert.AlertType.WARNING);
        alert.setTitle("提示");
        alert.setContentText(message);

        alert.showAndWait();
    }

}
